package model;

import enums.ExtensionEnum;
import enums.PremisaTypeEnum;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/*

    This file is part of Logica-Logike.

    Logica-Logike is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation version 3 of the License.

    Logica-Logike is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Logica-Logike.  If not, see <http://www.gnu.org/licenses/>.

 */
/**
 * Modela un polisilogismo;
 * @author Jose Martin Rozanec;
 */
public class Polisilogismo implements Serializable {
    private List<Premisa> premisaList;

    /**
     * Constructor;
     */
    public Polisilogismo() {
        premisaList = new ArrayList<Premisa>();
    }

    /**
     * Verifica si el polisilogismo ascendente se halla completo;
     *
     * @param premisaMayor;
     * @param premisaMenor;
     * @return boolean;
     */
    public boolean ascendenteIsComplete(Premisa premisaMayor, Premisa premisaMenor) {
        Sylogism sylogism = new Sylogism();
        sylogism.setPremisa(premisaMayor, PremisaTypeEnum.FIRST);
        sylogism.setPremisa(premisaMenor, PremisaTypeEnum.SECOND);
        sylogism.setPremisa(premisaList.get(0), PremisaTypeEnum.CONCLUSION);
        return sylogism.isComplete();
    }

    /**
     * Verifica si el polisilogismo descendente se halla completo;
     *
     * @param premisaMenor;
     * @param conclusion;
     * @return boolean;
     */
    public boolean descendenteIsComplete(Premisa premisaMenor, Premisa conclusion) {
        Sylogism sylogism = new Sylogism();
        sylogism.setPremisa(premisaList.get(premisaList.size() - 1), PremisaTypeEnum.FIRST);
        sylogism.setPremisa(premisaMenor, PremisaTypeEnum.SECOND);
        sylogism.setPremisa(conclusion, PremisaTypeEnum.CONCLUSION);
        return sylogism.isComplete();
    }

    /**
     * Permite agregar una silogismo de forma ascendente;
     *
     * @param premisaMayor;
     * @param premisaMenor;
     */
    public void addAscendente(Premisa premisaMayor, Premisa premisaMenor) {
        premisaList.add(0, premisaMenor);
        premisaList.add(0, premisaMayor);
    }

    /**
     * Permite agregar una silogismo de forma descendente;
     *
     * @param premisaMenor;
     * @param conclusion;
     */
    public void addDescendente(Premisa premisaMenor, Premisa conclusion) {
        premisaList.add(premisaMenor);
        premisaList.add(conclusion);
    }

    /**
     * Valida si el posible silogismo ascendente es valido;
     *
     * @param premisaMayor;
     * @param premisaMenor;
     * @return boolean;
     */
    public boolean validateAscendente(Premisa premisaMayor, Premisa premisaMenor) {
        Sylogism sylogism = new Sylogism();
        sylogism.setPremisa(premisaMayor, PremisaTypeEnum.FIRST);
        sylogism.setPremisa(premisaMenor, PremisaTypeEnum.SECOND);
        sylogism.setPremisa(premisaList.get(0), PremisaTypeEnum.CONCLUSION);
        return sylogism.validate();
    }

    /**
     * Valida si el posible silogismo descendente es valido;
     *
     * @param premisaMenor;
     * @param conclusion;
     * @return boolean;
     */
    public boolean validateDescendente(Premisa premisaMenor, Premisa conclusion) {
        Sylogism sylogism = new Sylogism();
        sylogism.setPremisa(premisaList.get(premisaList.size() - 1), PremisaTypeEnum.FIRST);
        sylogism.setPremisa(premisaMenor, PremisaTypeEnum.SECOND);
        sylogism.setPremisa(conclusion, PremisaTypeEnum.CONCLUSION);
        return sylogism.validate();
    }

    /**
     * Permite setear el silogismo inicial del polisilogismo;
     *
     * @param sylogism;
     */
    public void setInitialSylogism(Sylogism sylogism) {
        premisaList.add(sylogism.getPremisa(PremisaTypeEnum.FIRST));
        premisaList.add(sylogism.getPremisa(PremisaTypeEnum.SECOND));
        premisaList.add(sylogism.getPremisa(PremisaTypeEnum.CONCLUSION));
    }

    /**
     * Verifica si al polisilogismo ya le fue seteado el primer silogismo;
     *
     * @return boolean;
     */
    public boolean initialSylogismWasSet() {
        return premisaList.size() != 0;
    }

    /**
     * Devuelve una representacion en String del polisilogismo;
     *
     * @return String;
     */
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer();
        if (!premisaList.isEmpty()) {
            stringBuffer.append(premisaList.get(0).toString() + "\n");
            for (int j = 1; j < premisaList.size(); j++) {
                if (j % 2 == 0) {
                    stringBuffer.append("______________________________\n");
                }
                if (premisaList.get(j) != null) {
                    stringBuffer.append(premisaList.get(j).toString() + "\n");
                } else {
                    stringBuffer.append("" + "\n");
                }
            }
        }
        return stringBuffer.toString();
    }

    /**
     * Permite obtener el silogismo situado en la parte superior del polisilogismo;
     *
     * @return Sylogism;
     */
    public Sylogism getFirstSylogism() {
        Sylogism sylogism = new Sylogism();
        sylogism.setPremisa(premisaList.get(0), PremisaTypeEnum.FIRST);
        sylogism.setPremisa(premisaList.get(1), PremisaTypeEnum.SECOND);
        sylogism.setPremisa(premisaList.get(2), PremisaTypeEnum.CONCLUSION);
        return sylogism;
    }

    /**
     * Permite obtener el silogismo situado en la parte inferior del polisilogismo;
     *
     * @return Sylogism;
     */
    public Sylogism getLastSylogism() {
        Sylogism sylogism = new Sylogism();
        int last = premisaList.size();
        sylogism.setPremisa(premisaList.get(--last), PremisaTypeEnum.CONCLUSION);
        sylogism.setPremisa(premisaList.get(--last), PremisaTypeEnum.SECOND);
        sylogism.setPremisa(premisaList.get(--last), PremisaTypeEnum.FIRST);
        return sylogism;
    }

    /**
     * Permite obtener una lista con todos los silogismos del polisilogismo;
     *
     * @return List<Sylogism>;
     */
    public List<Sylogism> getIterator() {
        List<Sylogism> sylogismList = new ArrayList<Sylogism>();
        Sylogism sylogism;
        int first = 0;
        int second = 1;
        int conclusion = 2;
        while (conclusion < premisaList.size()) {
            sylogism = new Sylogism();
            sylogism.setPremisa(premisaList.get(first), PremisaTypeEnum.FIRST);
            sylogism.setPremisa(premisaList.get(second), PremisaTypeEnum.SECOND);
            sylogism.setPremisa(premisaList.get(conclusion), PremisaTypeEnum.CONCLUSION);
            sylogismList.add(sylogism);
            first += 2;
            second += 2;
            conclusion += 2;
        }
        return sylogismList;
    }

    /**
     * Permite agregar una premisa;
     *
     * @param premisa;
     */
    public void addPremisa(Premisa premisa) {
        premisaList.add(premisa);
    }

    /**
     * Devuelve un String con la representacion XML del polisilogismo;
     *
     * @return String;
     */
    public String toXML() {
        StringBuffer stringBuffer = new StringBuffer("<polisylogism>");
        for (int j = 0; j < premisaList.size(); j++) {
            stringBuffer.append(premisaList.get(j).toXML());
        }
        stringBuffer.append("</polisylogism>");
        return stringBuffer.toString();
    }

    /**
     * Interpreta un String XML y crea un objeto Polisilogismo acorde al XML;
     *
     * @param xml;
     * @return Polisilogismo;
     */
    public static Polisilogismo parseXML(String xml) {
        xml = xml.replace(openTag(), "");
        xml = xml.replace(closeTag(), "");
        xml = xml.replace(Premisa.openTag(), "");
        String[] premisaStrings = xml.split(Premisa.closeTag());
        Polisilogismo polisilogismo = new Polisilogismo();
        for (int j = 0; j < premisaStrings.length; j++) {
            if (!premisaStrings[j].equals("")) {
                polisilogismo.addPremisa(new Premisa(premisaStrings[j]));
            }
        }
        return polisilogismo;
    }

    /**
     * Devuelve el tag de apertura de la representacion XML del polisilogismo;
     *
     * @return String;
     */
    public static String openTag() {
        return "<polisylogism>";
    }

    /**
     * Devuelve el tag de clausura de la representacion XML del polisilogismo;
     *
     * @return String;
     */
    public static String closeTag() {
        return "</polisylogism>";
    }

    public static String ascendenteSuggestion(ExtensionEnum extension) {
        switch (extension) {
            case A:
                return "Primera figura: AAA\nSegunda figura: \nTercera figura: \nCuarta figura: ";
            case E:
                return "Primera figura: EAE\nSegunda figura: AEE/EAE\nTercera figura: \nCuarta figura: AEE";
            case I:
                return "Primera figura: AII\nSegunda figura: \nTercera figura: AAI/AII/IAI\nCuarta figura: AAI/IAI";
            case O:
                return "Primera figura: EIO\nSegunda figura: AOO/EIO\nTercera figura: EAO/OAO\nCuarta figura: EAO/EIO";

        }
        return "";
    }

    public static String descendenteSuggestion(ExtensionEnum extension) {
        switch (extension) {
            case A:
                return "Primera figura: AAA/AAI\nSegunda figura: \nTercera figura: \nCuarta figura: ";
            case E:
                return "Primera figura: EAE/EIO\nSegunda figura: EAE/EIO\nTercera figura: EAO/EIO\nCuarta figura: EAO/EIO";
            case I:
                return "Primera figura: \nSegunda figura: \nTercera figura: IAI\nCuarta figura: IAI";
            case O:
                return "Primera figura: \nSegunda figura: \nTercera figura: OAO\nCuarta figura: ";

        }
        return "";
    }

    public static Polisilogismo getPolisilogismoFromSylogisms(List<Sylogism> list) {
        Polisilogismo polisilogismo = new Polisilogismo();
        if (list.size() > 0) {
            polisilogismo.setInitialSylogism(list.get(0));
            for (int j = 1; j < list.size(); j++) {
                polisilogismo.addDescendente(list.get(j).getPremisa(PremisaTypeEnum.SECOND),
                        list.get(j).getPremisa(PremisaTypeEnum.CONCLUSION));
            }
        }
        return polisilogismo;
    }
}
